package cn.rdtimes.wolfdsp.core.util;

import java.util.Objects;

/**
 * 单链实现列表，长度应该控制在64以内
 * 使用id作为键
 *
 * @author BZ
 */
public class SimpleList<T> {
    private Node<T> first;
    private int size;

    public SimpleList() {
        // nothing
    }

    private void linkFirst(String id, T data) {
        Node<T> node = new Node<>(null, id, data);
        Node<T> f = first;
        first = node;
        if (f != null) {
            node.next = f;
        }
        size++;
    }

    private void link(String id, T data) {
        Node<T> node = new Node<>(null, id, data);
        Node<T> n = first;
        first = node;
        if (n != null) {
            first = node;
        } else {
            for (; n.next != null; ) n = n.next;
            n.next = node;
        }
        size++;
    }

    private T unlinkFirst() {
        final Node<T> f = first;
        T item = f.data;
        Node<T> next = f.next;
        f.id = null;
        f.data = null;
        f.next = null;
        first = next;
        size--;
        return item;
    }

    private T unlink(String id) {
        Node<T> n = first;
        Node<T> p = null;
        for (; n != null; ) {
            if (n.id.equals(id)) {
                T item = n.data;
                if (n == first) {
                    first = n.next;
                } else {
                    p.next = n.next;
                }
                n.id = null;
                n.data = null;
                n.next = null;
                size--;
                return item;
            }
            p = n;
            n = n.next;
        }
        return null;
    }

    private Node<T> node(String id) {
        Node<T> n = first;
        for (; n != null; ) {
            if (n.id.equals(id)) return n;
            n = n.next;
        }
        return null;
    }

    private void checkId(String id) {
        if (id == null || id.equals(""))
            throw new NullPointerException();
    }

    public void addFirst(String id, T data) {
        checkId(id);
        linkFirst(id, data);
    }

    public void add(String id, T data) {
        checkId(id);
        link(id, data);
    }

    public T removeFirst() {
        Node<T> f = first;
        return f == null ? null : unlinkFirst();
    }

    public T remove(String id) {
        checkId(id);
        return unlink(id);
    }

    public T getFirst() {
        Node<T> f = first;
        return f == null ? null : f.data;
    }

    public T get(String id) {
        checkId(id);
        Node<T> n = node(id);
        return n == null ? null : n.data;
    }

    public T set(String id, T data) {
        checkId(id);
        Node<T> node = node(id);
        if (node != null) {
            T item = node.data;
            node.data = data;
            return item;
        }
        return null;
    }

    public int size() {
        return size;
    }

    public T indexOf(String id) {
        checkId(id);
        Node<T> n = node(id);
        return n == null ? null : n.data;
    }

    public boolean contains(String id) {
        return indexOf(id) != null;
    }

    public String[] ids() {
        if (size == 0) return new String[0];
        else {
            String[] ret = new String[size];
            Node<T> n = first;
            int i = 0;
            for (; n != null; ) {
                ret[i] = n.id;
                i++;
                n = n.next;
            }
            return ret;
        }
    }

    public Object[] values() {
        if (size == 0) return (new Object[0]);
        else {
            Object[] ret = new Object[size];
            Node<T> n = first;
            int i = 0;
            for (; n != null; ) {
                ret[i] = n.data;
                i++;
                n = n.next;
            }
            return ret;
        }
    }


    public void clear() {
        Node<T> n = first;
        for (; n != null; ) {
            Node<T> next = n.next;
            n.id = null;
            n.data = null;
            n.next = null;
            n = next;
        }
        first = null;
        size = 0;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof SimpleList)) return false;

        SimpleList<?> list = (SimpleList<?>) o;
        if (size != list.size) return false;

        Node<?> x = first;
        Node<?> x1 = list.first;
        for (; x != null && x1 != null; ) {
            if (!(Objects.equals(x.id, x1.id))) {
                return false;
            }
            x = x.next;
            x1 = x1.next;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hashCode = 1;
        Node<T> n = first;
        for (; n != null; ) {
            String id = n.id;
            hashCode = 31 * hashCode + (id == null ? 0 : id.hashCode());
            n = n.next;
        }
        return hashCode;
    }

    static class Node<T> {
        private Node<T> next;
        private String id;
        private T data;

        public Node(Node<T> next, String id, T data) {
            this.next = next;
            this.id = id;
            this.data = data;
        }
    }
}
